package com.jgp.security.service;

import com.jgp.common.utils.ScannerUtil;
import com.jgp.security.annotation.Power;
import com.jgp.security.secmodel.SecResource;
import com.jgp.security.secrepository.SecResourceRepository;
import com.jgp.sys.annotation.PowerGroup;
import com.jgp.sys.annotation.PowerType;
import com.jgp.sys.query.Operator;
import com.jgp.sys.query.QueryFilterList;
import com.jgp.sys.ui.Pager;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2019-11-03
 */
@Service
@Transactional(transactionManager = "secondTransactionManager",readOnly = true)
public class SecResourceService {
    
    @Lazy
    @Autowired
    private SecResourceRepository repository;
    
    
    @Transactional(transactionManager = "secondTransactionManager")
    public void scanAndGenerate() {
        Class[] annotations = new Class[]{RestController.class, Controller.class, Service.class};
        String[] pkgs = new String[]{"com.**.controller.**", "com.**.service.**"};
        List<String> all = repository.readAll().stream().map(SecResource::getId).collect(Collectors.toList());
        List<String> needs = new ArrayList<>();
        ScannerUtil.scanByAnnotation(annotations, pkgs).forEach(o -> {
            Class<?> clazz = (Class) o;
            PowerType type = null;
            PowerGroup groupPower = clazz.getAnnotation(PowerGroup.class);
            if (Objects.isNull(groupPower)) {
                return;
            }
            String groupRemark = groupPower.value();
            String groupName = clazz.getName();
            
            if (Objects.nonNull(clazz.getAnnotation(RestController.class))) {
                type = PowerType.API;
                groupRemark += "-异步操作";
            } else if (Objects.nonNull(clazz.getAnnotation(Controller.class))) {
                type = PowerType.PAGE;
                groupRemark += "-访问控制";
            } else if (Objects.nonNull(clazz.getAnnotation(Service.class))) {
                type = PowerType.SERVICE;
                groupRemark += "-服务";
            }
            
            final PowerType finalType = type;
            String finalGroupRemark = groupRemark;
            String finalGroupName = groupName;
            Arrays.asList(clazz.getMethods()).forEach(method -> {
                Power annotation = method.getAnnotation(Power.class);
                if (Objects.nonNull(annotation)) {
                    SecResource res = new SecResource(finalType, finalGroupName + ":" + method.getName(), annotation.remark(), finalGroupName,
                                                      finalGroupRemark
                    );
                    SecResource oldRes = repository.findTop1ByAction(res.getAction());
                    if (Objects.nonNull(oldRes)) {
                        oldRes.setRemark(res.getRemark());
                        oldRes.setPowerType(res.getPowerType());
                        needs.add(repository.update(oldRes).getId());
                    } else {
                        needs.add(repository.create(res).getId());
                    }
                }
            });
        });
        List<String> deleteIds = all.stream().filter(id -> !needs.contains(id)).collect(Collectors.toList());
        if (Objects.nonNull(deleteIds) && deleteIds.size() > 0) repository.deleteInBatchPersist(repository.readAll(deleteIds));
    }
    
    public List<SecResource> query(String action, String remark, PowerType powerType, Pager pager) {
        QueryFilterList filters = filters(action, remark, powerType);
        return repository.read(filters, pager);
    }
    
    private QueryFilterList filters(String action, String remark, PowerType powerType) {
        QueryFilterList filters = new QueryFilterList();
        if (StringUtils.isNotBlank(action)) filters.addFilter("action", Operator.eq, action);
        if (StringUtils.isNotBlank(remark)) filters.addFilter("remark", Operator.like, remark);
        if (Objects.nonNull(powerType)) filters.addFilter("powerType", Operator.eq, powerType);
        return filters;
    }
}
